﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using AForge.Math;

namespace MagicCube_v2_Demo
{
    public partial class Form1 : Form
    {

        /*************************************************
         * 定义变量
         * **********************************************/
        public  Bitmap bmpSourceImage;
        public string strSourceImage;
        public byte[] byteDMBinary = new byte[512];
        public Bitmap bmpInsertedImage = null;
        public Form1()
        {
            InitializeComponent();
        }


        //打开图片
        private void btnOpenImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofdSourceImage = new OpenFileDialog();
            ofdSourceImage.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +
                "*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf|" +
                "位图( *.bmp; *.jpg; *.png;...) | *.bmp; *.pcx; *.png; *.jpg; *.gif; *.tif; *.ico|" + "矢量图( *.wmf; *.eps; *.emf;...) | *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";     //为图像创建筛选器
            //设置标题
            ofdSourceImage.Title = "打开图片";
            //关闭帮助按钮
            ofdSourceImage.ShowHelp = false;
            
            //打开图像
            if (ofdSourceImage.ShowDialog() == DialogResult.OK)
            {
                strSourceImage = ofdSourceImage.FileName;
                bmpSourceImage = (Bitmap)Image.FromFile(strSourceImage);
                if (bmpSourceImage.Width == 512 && bmpSourceImage.Height == 512 && bmpSourceImage.PixelFormat == PixelFormat.Format8bppIndexed)
                {
                    pbSourceImage.Image = bmpSourceImage;
                    tabControl1.SelectedIndex = 1;
                }
                else
                {
                    MessageBox.Show( "该demo版本只支持512*512的8位图像，请重新选择!","提示：");
                }
                
            }
        }



        //生成二维码
        private void btnCreateDM_Click(object sender, EventArgs e)
        {
            ////获得二进制码流的长度
            //int len = tbBinary.Text.Length;
            //MessageBox.Show("生成二维码的功能稍后完成！"+len, "提示：");
            if (tbInfo.Text.Length>=1 && tbInfo.Text.Length <= 15)
            {
                string strBinary = null;
                DataMatrix DM = new DataMatrix();
                DM.Create(tbInfo.Text);
                pbDM.Image = (Bitmap)DM.bmp;
                byteDMBinary = (byte[])DM.param2.Clone();
                for (int i = 0; i < DM.cpara.Length; i++)
                {
                    byte tmp = (byte)DM.cpara[i];
                    strBinary += tmp.ToString();
                }
                tbBinary.Text = strBinary;
                label4.Text = "字符长度：" + DM.cpara.Length;
            }
            else
            {
                MessageBox.Show("您还没有输入信息或者输入的信息超过30个字符，请重新输入！", "提示：", MessageBoxButtons.OK);
            }
            tabControl1.SelectedIndex = 0;
            
        }


        //嵌入水印信息
        private void btnInsert_Click(object sender, EventArgs e)
        {
            if (bmpSourceImage != null && byteDMBinary!=null)
            {
                //位图矩形
                Rectangle rect = new Rectangle(0, 0, bmpSourceImage.Width, bmpSourceImage.Height);
                //以可读写的方式锁定全部位图像素
                System.Drawing.Imaging.BitmapData bmpSourceData = bmpSourceImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmpSourceImage.PixelFormat);
                //获得首地址
                IntPtr ptr = bmpSourceData.Scan0;

                //定义源图像的数据数组
                int bytes = bmpSourceData.Width * bmpSourceData.Height;
                byte[] bmpSourceBytes = new byte[bytes];
                //复制被锁定的位图像素值到该数组内
                System.Runtime.InteropServices.Marshal.Copy(ptr, bmpSourceBytes, 0, bytes);
                bmpSourceImage.UnlockBits(bmpSourceData);
                //图像分割
               byte[,] byte256Bmp = new byte[16*16,32*32];
               byte256Bmp = ImageCut(bmpSourceBytes ,16);
               Complex[,] cpx256BMP = new Complex[16 * 16, 32 * 32];
               for (int i = 0; i < 16 * 16; i++)
               {
                   byte[] byteTmp = new byte [32*32];
                   Complex[] compTmp = new Complex[32 * 32];
                   for (int j = 0; j < 32 * 32; j++)
                   {
                       byteTmp[j] = byte256Bmp[i,j];
                   }
                   compTmp = FourierTranform.fft2(byteTmp, 32, 32, true);
                   for (int j = 0; j < 32 * 32; j++)
                   {
                       cpx256BMP[i, j] = compTmp[j];
                   }
               }

                //嵌入
               InsertWM(byteDMBinary,ref cpx256BMP);

                //逆变换
               for (int i = 0; i < 256; i++)
               {
                   Complex[] cpxTmp = new Complex[1024];
                   for (int j = 0; j < 1024; j++)
                   {
                       cpxTmp[j] = cpx256BMP[i, j];
                   }

                   byte[] byteTmp = new byte[1024];
                   byteTmp = FourierTranform.ifft2(cpxTmp, 32, 32, true);
                   for (int j = 0; j < 256; j++)
                   {
                       byte256Bmp[i, j] = byteTmp[j];
                   }
               }

                //把分块数据合并到一起
               byte[] byteInsertedImage = new byte[512 * 512];
                byteInsertedImage = ImageMerge(byte256Bmp, 16);
                //重新生成图像
               Rectangle rect1 = new Rectangle(0, 0, 512, 512);
                bmpInsertedImage = new Bitmap(512, 512, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                System.Drawing.Imaging.BitmapData bmpInsertedData = bmpInsertedImage.LockBits(rect1, ImageLockMode.ReadWrite, bmpInsertedImage.PixelFormat);
                IntPtr ptrInserted = bmpInsertedData.Scan0;
                System.Runtime.InteropServices.Marshal.Copy(byteInsertedImage, 0, ptrInserted, 512 * 512);
                bmpInsertedImage.UnlockBits(bmpInsertedData);
                bmpInsertedImage.Palette = bmpSourceImage.Palette;
                pbInsertedImage.Image = bmpInsertedImage;
                tabControl1.SelectedIndex = 2;
            }
            else
            {
                MessageBox.Show("您还没有选择图片，请选择图片。", "提示：", MessageBoxButtons.OK);
                tabControl1.SelectedIndex = 1;
            }
        }

        /**************************************************
         * 图像分割
         * bmpSourceBytes:源图像数据
         * num：把图像分割成num*num块
         * ************************************************/
        private static byte[,] ImageCut(byte[] bmpSourceBytes, int num)
        {
            byte[,] bmpBytes = new byte[num * num, 512 / num * 512 / num];
            for (int y = 0; y < num; y++)
            {
                for (int x = 0; x < num; x++)
                {
                    for (int j = y * 32; j < (y + 1) * 32; j++)
                    {
                        for (int i = x * 32; i < (x + 1) * 32; i++)
                        {
                            bmpBytes[16 * x + y, i % 32 * 32 + j % 32] = bmpSourceBytes[i*512+j];
                        }
                    }
                }
            }

            return bmpBytes;

        }

        /*****************************************************************************
         * 合并分块图像数据
         * **************************************************************************/
        private static byte[] ImageMerge(byte[,] bmpBytes, int num)
        {
            byte[] byteInsertedBmp = new byte[512 * 512];
            for (int y = 0; y < num; y++)
            {
                for (int x = 0; x < num; x++)
                {
                    for (int j = y * 32; j < (y + 1) * 32; j++)
                    {
                        for (int i = x * 32; i < (x + 1) * 32; i++)
                        {
                            byteInsertedBmp[i * 512 + j] = bmpBytes[16 * x + y, i % 32 * 32 + j % 32];
                        }
                    }
                }
            }

            return byteInsertedBmp;
        }



        /*******************************************************
         * 嵌入水印
         * byte[] byteWM :需要嵌入的水印信息
         * ref Complex[] :需要嵌入水印的载体
         * 规格要求：compBMP[256,1024],byteWM[512];
         * ***********************************************/
        private static void InsertWM(byte[] byteWM,  ref Complex[,] compBMP)
        {
            //嵌入强度
            int r = 1;
            byte[,] byteData = new byte[256, 2];
            for (int i = 0; i < 256; i++)
            {
                byteData[i, 0] = byteWM[2 * i];
                byteData[i, 1] = byteWM[2 * i + 1];
            }

            for (int i = 0; i < 256; i++)
            {
                compBMP[i, 7 * 32 + 7].Re = compBMP[i, 23 * 32 + 23].Re = compBMP[i, 7 * 32 + 7].Re * (1 + r * byteData[i, 0]);
                compBMP[i, 7 * 32 + 23].Re = compBMP[i, 23 * 32 + 7].Re = compBMP[i, 7 * 32 + 23].Re * (1 + r * byteData[i, 1]);
            }
        }

        //提取水印信息
        private void btnGetWM_Click(object sender, EventArgs e)
        {
            ////读取嵌入水印的图片，如果图片都没有打开，则提示打开图片
            if (bmpInsertedImage != null && bmpSourceImage != null)
            {
                //如果是验证刚刚嵌入的图片，则处理bmpInsertedImage图片，否则处理重新打开的图片
                if (bmpInsertedImage != null)
                {
                    bmpSourceImage = bmpInsertedImage;
                }
                else
                {
                    Rectangle rect = new Rectangle(0, 0, bmpSourceImage.Width, bmpSourceImage.Height);
                    System.Drawing.Imaging.BitmapData bmpData = bmpSourceImage.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
                    IntPtr ptr = bmpData.Scan0;

                    int bytes = bmpData.Width * bmpData.Height;
                    byte[] bmpSourceBytes = new byte[bytes];
                    System.Runtime.InteropServices.Marshal.Copy(ptr, bmpSourceBytes, 0, bytes);

                }
            }
        }
    }
}
